<template>
  <a-modal
    :key="moveModalKey"
    v-model:visible="dialogShow"
    unmount-on-close
    :on-before-ok="
      () => okFunction(config.type === 0 ? getFolderKey : getDataByCheckedKeys)
    "
    @cancel="handleCancel"
  >
    <template #title>
      {{ config.type === 0 ? '选择目标文件夹' : '添加文件' }}
    </template>
    <div>
      <a-tree
        ref="tree"
        v-model:checked-keys="checkedKeys"
        v-model:expanded-keys="expendedKeys"
        :checkable="true"
        :check-strictly="config.type === 0"
        :data="treeData"
        :load-more="config.type === 0 ? loadMoreFolder : loadMoreFolderAndFile"
        @check="config.type === 0 ? checkNode($event) : null"
      />
    </div>
  </a-modal>
</template>

<script lang="ts" setup>
  import { ref, watch, defineProps, computed, onMounted } from 'vue';
  import {
    getChildFolderList,
    getFileList,
    FileAndFolderNodeMessage,
    FolderMessage,
    FileMessage,
  } from '@/api/tree-folder';
  import { useRoute } from 'vue-router';
  import treeDefault from './json/tree-default.json';

  const props = defineProps({
    visible: {
      type: Boolean,
      required: false,
    },
    okFunction: {
      type: Function as () => any,
      required: true,
    },
    config: {
      type: Object,
      default: () => {
        return {
          type: 0, // 0：文件夹模式 1：文件夹+文件模式
        };
      },
    },
  });

  const route = useRoute();
  const moveModalKey = ref(0);
  const checkedKeys = ref<(string | number)[]>([]);
  const expendedKeys = ref<(string | number)[]>(['wip']);
  const emit = defineEmits(['update:visible']);
  const tree = ref();
  const { projectId }: any = route.params;
  const treeData = ref<FileAndFolderNodeMessage[]>(treeDefault);
  // treeData初始化
  if (props.config.type === 0) {
    treeData.value[0].disableCheckbox = true;
    treeData.value = [treeData.value[0]];
  }

  // 弹窗开关
  const dialogShow = computed({
    get: () => props.visible,
    set: (val) => emit('update:visible', val),
  });

  // 弹窗关闭事件
  const handleCancel = () => {
    emit('update:visible', false);
  };

  // 点击checkbox触发事件
  const checkNode = (checkeds: (string | number)[]) => {
    if (checkeds.length > 1) {
      const key = checkeds[1];
      checkedKeys.value = [key];
    }
  };

  // 给接口获取的tree数据添加节点信息
  const handleTreeDataToNode = (
    list: FolderMessage[] | FileMessage[]
  ): FileAndFolderNodeMessage[] => {
    const treeNodes: FileAndFolderNodeMessage[] = [];
    list.forEach((item) => {
      const node: FileAndFolderNodeMessage = {
        ...item,
        isFileOrFolder: 'folderId' in item ? 1 : 0,
        key: item.id,
        title: item.name,
        children: [],
        isLeaf: 'folderId' in item,
      };
      treeNodes.push(node);
    });
    return treeNodes;
  };

  // 获取根目录
  const init = async () => {
    const res = await getChildFolderList(projectId, undefined, 'WIP', '0');
    const { list } = res.data;
    const treeNodes: FileAndFolderNodeMessage[] = handleTreeDataToNode(list);
    treeData.value[0].children = treeNodes;
  };

  // 动态加载文件夹和文件节点
  const loadMoreFolderAndFile = async (nodeData: FileAndFolderNodeMessage) => {
    let children: FileAndFolderNodeMessage[] = [];
    const promiseList = [
      await getChildFolderList(
        nodeData.projectId,
        nodeData.teamId,
        nodeData.type,
        nodeData.id
      ),
      await getFileList(nodeData.id),
    ];
    const res = await Promise.all(promiseList);
    const folderList: FileAndFolderNodeMessage[] = handleTreeDataToNode(
      res[0]?.data.list || []
    );
    const fileList: FileAndFolderNodeMessage[] = handleTreeDataToNode(
      res[1]?.data.list || []
    );
    children = [...folderList, ...fileList];
    nodeData.children = children;
  };

  // 动态加载文件夹节点
  const loadMoreFolder = async (nodeData: FileAndFolderNodeMessage) => {
    const res = await getChildFolderList(
      nodeData.projectId,
      nodeData.teamId,
      nodeData.type,
      nodeData.id
    );
    const folderList: FileAndFolderNodeMessage[] = handleTreeDataToNode(
      res.data.list || []
    );
    nodeData.children = folderList;
  };

  onMounted(() => {
    init();
  });

  // 获取选中的文件（完整的文件结构）
  const getDeepNode = async (
    treeList: FileAndFolderNodeMessage[],
    checkedNodeKeys: (string | number | undefined)[],
    halfCheckedNodeKeys: (string | number | undefined)[],
    fatherChecked = false
  ) => {
    const result: FileAndFolderNodeMessage[] = [];
    for (let i = 0; i < treeList.length; i++) {
      const treeItem: any = treeList[i];
      if (
        // 半选状态
        halfCheckedNodeKeys.includes(treeItem.key || '')
      ) {
        // eslint-disable-next-line no-await-in-loop
        treeItem.children = await getDeepNode(
          treeItem.children || [],
          checkedNodeKeys,
          halfCheckedNodeKeys
        );
        result.push(treeItem);
      } else if (
        // 全选状态 或者 父节点是全选状态 并且 是文件节点
        (checkedNodeKeys.includes(treeList[i].key || '') || fatherChecked) &&
        treeItem.folderId
      ) {
        result.push(treeItem);
      } else if (
        // 全选状态 或者 父节点是全选状态 并且 没有子节点
        (checkedNodeKeys.includes(treeList[i].key || '') || fatherChecked) &&
        treeItem?.children.length === 0
      ) {
        let children: FileAndFolderNodeMessage[] = [];

        const promiseList = [
          // eslint-disable-next-line no-await-in-loop
          await getChildFolderList(
            treeItem.projectId,
            treeItem.teamId,
            treeItem.type,
            treeItem.id
          ),
          // eslint-disable-next-line no-await-in-loop
          await getFileList(treeItem.id),
        ];
        // eslint-disable-next-line no-await-in-loop
        const res = await Promise.all(promiseList);
        const folderList: FileAndFolderNodeMessage[] = handleTreeDataToNode(
          res[0]?.data.list || []
        );
        const fileList: FileAndFolderNodeMessage[] = handleTreeDataToNode(
          res[1]?.data.list || []
        );
        children = handleTreeDataToNode([...folderList, ...fileList]);
        treeItem.children = children;

        // eslint-disable-next-line no-await-in-loop
        treeItem.children = await getDeepNode(
          treeItem.children || [],
          checkedNodeKeys,
          halfCheckedNodeKeys,
          true
        );
        result.push(treeItem);
      } else if (
        // 全选状态 并且 有一个以上子节点
        checkedNodeKeys.includes(treeList[i].key || '') &&
        treeItem?.children.length > 0
      ) {
        // eslint-disable-next-line no-await-in-loop
        treeItem.children = await getDeepNode(
          treeItem.children || [],
          checkedNodeKeys,
          halfCheckedNodeKeys,
          true
        );
        result.push(treeItem);
      }
    }
    return result;
  };

  // 过滤空文件夹
  const emptyFolderFilter = (treeList: FileAndFolderNodeMessage[]) => {
    const result: FileAndFolderNodeMessage[] = [];
    treeList.forEach((item) => {
      if (item.isFileOrFolder === 1) {
        result.push(item);
      } else {
        const childrenResult = emptyFolderFilter(item.children || []);
        if (childrenResult.length !== 0) {
          item.children = childrenResult;
          result.push(item);
        }
      }
    });
    return result;
  };

  // 根据选中的节点得到节点信息
  const getDataByCheckedKeys = async () => {
    const checkedNodes: FileAndFolderNodeMessage[] =
      tree.value.getCheckedNodes();
    const halfCheckedNodes: FileAndFolderNodeMessage[] =
      tree.value.getHalfCheckedNodes();
    const checkedNodeKeys = checkedNodes.map((item) => item.key);
    const halfCheckedNodeKeys = halfCheckedNodes.map((item) => item.key);
    const treeDataClone = JSON.parse(JSON.stringify(treeData.value));
    const deepResult = await getDeepNode(
      treeDataClone,
      checkedNodeKeys || [],
      halfCheckedNodeKeys
    );
    const result = emptyFolderFilter(deepResult);
    return result;
  };

  // 返回文件夹节点id
  const getFolderKey = () => {
    return checkedKeys.value.length ? checkedKeys.value[0] : '';
  };

  watch(props, (newValue) => {
    if (newValue.visible === false) {
      checkedKeys.value = [];
      moveModalKey.value++;
      const wipData: any = treeData.value[0].children;
      wipData?.forEach((item: any) => {
        item.children = [];
      });
      expendedKeys.value = ['wip'];
    }
  });
</script>
